﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.Collections.ObjectModel;

namespace SmartFront.Toolkit.Core
{
    public static class TypeExtensionMethods
    {
        /// <summary>
        /// Tries the parse.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
        /// <param name="val">The val.</param>
        /// <returns></returns>
        public static bool TryParseEnum<T>(object value, bool ignoreCase, out T val)
        {
            val = default(T);
            if (null != value)
            {
                if (value is T)
                {
                    val = (T)value;
                    return true;
                }
                else
                {
                    string valStr = value.ToString();
                    try
                    {
                        val = (T)Enum.Parse(typeof(T), valStr, ignoreCase);
                        return true;
                    }
                    catch
                    {
                        val = default(T);
                        return false;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Gets the actual type of the type from nullable.
        /// </summary>
        /// <param name="nullableType">Type of the nullable.</param>
        /// <returns></returns>
        public static Type GetActualTypeFromNullableType(this Type nullableType)
        {
            Type enumType = nullableType;

            if (enumType.IsGenericType && enumType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                enumType = Nullable.GetUnderlyingType(enumType);
                Debug.Assert(enumType != null);
            }

            return enumType;
        }

        /// <summary>
        /// Determines whether [is nullable type] [the specified nullable type].
        /// </summary>
        /// <param name="nullableType">Type of the nullable.</param>
        /// <returns>
        /// 	<c>true</c> if [is nullable type] [the specified nullable type]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullableType(this Type nullableType)
        {
            return nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        /// <summary>
        /// Gets the attribute.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="member">The member.</param>
        /// <returns></returns>
		public static T GetFirstAttribute<T>(this ICustomAttributeProvider member) where T : Attribute
		{
			object[] attr = member.GetCustomAttributes(typeof(T), false);
			if (attr.Length == 1)
			{
				return (T)attr[0];
			}
			else
			{
				return null;
			}
		}

        /// <summary>
        /// Gets the attributes.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        public static IEnumerable<T> GetAttributes<T>(this ICustomAttributeProvider member) where T : Attribute
        {
            object[] attr = member.GetCustomAttributes(typeof(T), false);
            if (attr.Length > 0)
            {
                Collection<T> coll = new Collection<T>();
                coll.AddRange(attr.OfType<T>());
                return coll;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Determines whether the specified member has attribute.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <param name="attribute">The attribute.</param>
        /// <returns>
        /// 	<c>true</c> if the specified member has attribute; otherwise, <c>false</c>.
        /// </returns>
		public static bool HasAttribute(this ICustomAttributeProvider member, Type attribute)
		{
			object[] attr = member.GetCustomAttributes(attribute, false);
            return attr.Length > 0;
		}
    }
}
